package com.hoshiicloud.payment.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hoshiicloud.common.aop.Logable;
import com.hoshiicloud.common.api.dto.EncryptedResponseDTO;
import com.hoshiicloud.common.constant.QueueConsts;
import com.hoshiicloud.common.exception.CommonError;
import com.hoshiicloud.common.exception.ServiceException;
import com.hoshiicloud.common.rpc.Response;
import com.hoshiicloud.common.utils.EncryptionUtil;
import com.hoshiicloud.payment.config.RabbitMQConfig;
import com.hoshiicloud.payment.config.RsaConfig;
import com.hoshiicloud.payment.Paylist;
import com.hoshiicloud.payment.enumeration.OrderType;
import com.hoshiicloud.payment.enumeration.TradeStatus;
import com.hoshiicloud.payment.param.CallBackRequest;
import com.hoshiicloud.payment.feign.IdGeneratorService;
import com.hoshiicloud.payment.mapper.PaylistMapper;
import com.hoshiicloud.payment.service.PaylistService;
import java.time.LocalDateTime;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author Mr.wu
 * @since 2019-05-13
 */
@Service
@Slf4j
public class PaylistServiceImpl extends ServiceImpl<PaylistMapper, Paylist> implements
        PaylistService {

    @Autowired
    private IdGeneratorService idGeneratorService;
    @Autowired
    private PaylistMapper paylistMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public Response callbackProcess(CallBackRequest param, OrderType orderType) {
        try {
            if (StringUtils.isBlank(param.getTradeNo())) {
                return Response.failed("订单号为空");
            }
            Paylist paylist=null;
            if(orderType.equals(OrderType.REFUND) ){
                QueryWrapper<Paylist> queryWrapper=new QueryWrapper<Paylist>();
                queryWrapper.lambda().eq(Paylist::getOrderId,param.getTradeNo());
                paylist=paylistMapper.selectOne(queryWrapper);
            } else if(orderType.equals(OrderType.PAY)){
                paylist = paylistMapper.selectById(param.getTradeNo());
            }
            if (paylist == null) {
                return Response.failed("订单不存在");
            }
            TradeStatus tradeStatus = TradeStatus.getByStatus(paylist.getStatus());
            if (TradeStatus.NOTPAY == tradeStatus) {
                //比对金额,如果金额不一致修改为订单状态异常
                if (paylist.getPayamount().compareTo(param.getAmount()) == 0) {
                    paylist.setStatus(TradeStatus.SUCCESS.getStatus());
                    paylist.setUpdatedTime(LocalDateTime.now());
                    paylist.setPayOutderno(param.getOutTradeNo());
                    paylist.setAmount(param.getAmount());
                    paylist.setPaytime(param.getPayTime());
                    paylistMapper.updateById(paylist);
                    // 使用消息队列处理
                    // 定义回调信息 并加密数据
                    Map<String, String> reqMap = new HashMap<String, String>();
                    reqMap.put("id", paylist.getId().toString());
                    reqMap.put("orderId", paylist.getOrderId());
                    reqMap.put("platformId", paylist.getPlatformId().toString());
                    reqMap.put("channel", paylist.getChannel().toString());
                    reqMap.put("attach",paylist.getAttach());
                    EncryptedResponseDTO req = EncryptionUtil
                            .encryptData(reqMap, RsaConfig.getClientPrivateKey(),
                                    RsaConfig.getServerPublicKey());
                    String base64Info = Base64.getEncoder()
                            .encodeToString(JSON.toJSONString(req).getBytes());
                    log.info("回调报文:" + base64Info);
                    switch (orderType) {
                        case PAY:
                            rabbitTemplate
                                    .convertAndSend(QueueConsts.PAY_CALLBACK_QUEUE, base64Info);
                            break;
                        case REFUND:
                            rabbitTemplate.convertAndSend(QueueConsts.REFUND_CALLBACK_QUEUE,
                                    base64Info);
                            break;
                        default:
                            break;
                    }
                    return Response.success("处理成功", paylist);
                } else {
                    paylist.setStatus(TradeStatus.PAYERROR.getStatus());
                    paylist.setUpdatedTime(LocalDateTime.now());
                    paylistMapper.updateById(paylist);
                    log.error("回调金额与订单金额不一致");
                    return Response.failed("回调金额与订单金额不一致");
                }
            } else {
                //订单不为可支付回调状态,发送成功回调消息并返回上游success
                // 使用消息队列处理
                // 定义回调信息 并加密数据
                Map<String, String> reqMap = new HashMap<String, String>();
                reqMap.put("id", paylist.getId().toString());
                reqMap.put("orderId", paylist.getOrderId());
                reqMap.put("platformId", paylist.getPlatformId().toString());
                reqMap.put("channel", paylist.getChannel().toString());
                reqMap.put("attach",paylist.getAttach());
                EncryptedResponseDTO req = EncryptionUtil
                        .encryptData(reqMap, RsaConfig.getClientPrivateKey(),
                                RsaConfig.getServerPublicKey());
                String base64Info = Base64.getEncoder()
                        .encodeToString(JSON.toJSONString(req).getBytes());
                log.info("回调报文:" + base64Info);
                switch (orderType) {
                    case PAY:
                        rabbitTemplate
                                .convertAndSend(QueueConsts.PAY_CALLBACK_QUEUE, base64Info);
                        break;
                    case REFUND:
                        rabbitTemplate.convertAndSend(QueueConsts.REFUND_CALLBACK_QUEUE,
                                base64Info);
                        break;
                    default:
                        break;
                }

                return Response.success("处理成功", paylist);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("回调处理异常",e);
            return Response.failed("回调处理异常" + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = "Paylist", allEntries = true)
    @Logable(authName = "支付服务--支付回调处理")
    public Response paymentProcess(CallBackRequest param) {
        log.info("支付回调处理开始------");
        Response result = callbackProcess(param, OrderType.PAY);
        log.info("支付回调处理结束------");
        return result;
    }

    @Override
    @Cacheable(cacheNames = "Paylist", key = "#root.targetClass.simpleName+':'+#root.methodName+':'+#payOrderId")
    @Logable(authName = "支付服务- -根据退款单ID 查询支付流水 ")
    public Paylist queryOneByPayOrderId(String payOrderId) {
        QueryWrapper<Paylist> q = new QueryWrapper<>();
        q.lambda().eq(Paylist::getOrderId,payOrderId) // orderId  被当做 退款单Id 使用
        .eq(Paylist::getPayType,1) // 1状态为消费
        .eq(Paylist::getStatus,1); // 1状态为已付款
        return baseMapper.selectOne(q);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = "Paylist", allEntries = true)
    @Logable(authName = "支付服务--退款回调处理")
    public Response refundProcess(CallBackRequest param) {
        log.info("退款回调处理开始------");
        Response result = callbackProcess(param, OrderType.REFUND);
        log.info("退款回调处理结束------");
        return result;
    }

    /**
     * @param id
     * @return com.hoshiicloud.payment.Paylist
     * @description: 根据id查询
     */
    @Override
    @Cacheable(cacheNames = "Paylist", key = "#root.targetClass.simpleName+':'+#root.methodName+':'+#id")
    @Logable(authName = "支付服务- -查询 ")
    public Paylist getById(Long id) {
        return baseMapper.selectById(id);
    }

    @Override
    @Logable(authName = "支付服务- -根据参数查询 ")
    @Cacheable(cacheNames = "Paylist", key = "#root.targetClass.simpleName+':'+#root.methodName+':'+#key")
    public List<Paylist> getByParam(QueryWrapper queryWrapper,String key) {
        return paylistMapper.selectList(queryWrapper);
    }

    /**
     * @param entity
     * @return boolean
     * @description: 新增
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = "Paylist", allEntries = true)
    @Logable(authName = "支付服务--新增")
    public boolean save(Paylist entity) {
        if (entity.getId() == null) {
            String id = idGeneratorService.queryGeneratorId();
            if (id == null || id == "") {
                throw new ServiceException(CommonError.error("新增失败"));
            }
            entity.setId(Long.parseLong(id));
        }
        entity.setCreatedTime(LocalDateTime.now());
        int row = baseMapper.insert(entity);
        if (row <= 0) {
            throw new ServiceException(CommonError.error("新增失败"));
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = "Paylist", allEntries = true)
    @Logable(authName = "支付服务--新增或更新")
    public boolean saveOrUpdate(Paylist entity) {
        if (entity.getId() == null) {
            String id = idGeneratorService.queryGeneratorId();
            if (id == null || id == "") {
                throw new ServiceException(CommonError.error("新增失败"));
            }
            entity.setId(Long.parseLong(id));
        }

        if(entity.getCreatedTime()==null){
            entity.setCreatedTime(LocalDateTime.now());
        }
        entity.setUpdatedTime(LocalDateTime.now());
        return super.saveOrUpdate(entity);
    }

    /**
     * @param entity
     * @return boolean
     * @description: 修改
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = "Paylist", allEntries = true)
    @Logable(authName = "支付服务-管理-修改")
    public boolean updateById(Paylist entity) {
        entity.setUpdatedTime(LocalDateTime.now());
        int row = baseMapper.updateById(entity);
        if (row <= 0) {
            throw new ServiceException(CommonError.error("修改失败"));
        }
        return true;
    }

    /**
     * @param queryWrapper
     * @return IPage
     * @description: 分页查询
     */
    @Override
    @Logable(authName = "支付服务-管理-分页查询")
    @Cacheable(cacheNames = "Paylist", key = "T(com.hoshiicloud.common.utils.DigestUtils).md5('Page(current=' + #page.getCurrent() + ', size=' + #page.getSize() + '), Wrapper(SqlSelect=' + #queryWrapper.getSqlSelect() + ', SqlSegment=' + #queryWrapper.getSqlSegment() + ',queryWrapper=' + #queryWrapper.toString() + ')')")
    public IPage<Paylist> page(IPage<Paylist> page, Wrapper<Paylist> queryWrapper) {
        return baseMapper.selectPage(page, queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = "Paylist", allEntries = true)
    @Logable(authName = "支付服务-管理-删除")
    public boolean deleteById(Paylist entity) {
        //entity.setUpdatedtime(LocalDateTime.now());
        //entity.setDeleted(1);
        int row = baseMapper.updateById(entity);
        if (row <= 0) {
            throw new ServiceException(CommonError.error("删除失败"));
        }
        return true;
    }
}
